﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Nacos.V2.Utils;
using System.Collections.Concurrent;
using System.Reflection;
using XYS.Core.Api;
using XYS.Core.Api.Attributes;
using XYS.Core.Api.Filters;
using XYS.Core.Models;
using XYS.Core.Util.Helper;
using XYS.Service.Core.Filters;

namespace XYS.Service.Core
{
    /// <summary>
    /// Swagger 相关配置
    /// </summary>
    public static class SwaggerExtension
    {
        /// <summary>
        /// OpenApiInfo Map
        /// 用于配置swagger
        /// </summary>
        public static readonly ConcurrentDictionary<string, OpenApiInfo> OpenApiInfoMap = new();

        /// <summary>
        /// 添加Swagger配置
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder)
        {
            OnAppBuilderAction.SwaggeringAction?.Invoke(builder);
            builder.Services.AddSwaggerGen();

            #region 配置 Swagger

            //反射获取所有控制器
            List<Type> baseControllers = AssemblyHelper.GetAssemblyTypes().Where(t => t != typeof(BaseController) && typeof(BaseController).IsAssignableFrom(t)).ToList();

            foreach (var controller in baseControllers)
            {
                //获取配置
                var openApiInfo = controller.GetCustomAttribute<OpenApiInfoAttribute>();
                if (openApiInfo != null && !string.IsNullOrWhiteSpace(openApiInfo.Name) && !OpenApiInfoMap.ContainsKey(openApiInfo.Name))
                {
                    OpenApiInfoMap[openApiInfo.Name] = new OpenApiInfo { Title = openApiInfo.Title, Version = openApiInfo.Version };
                }
            }

            //Add Swagger
            builder.Services.AddSwaggerGen(c =>
            {
                // 添加文档信息
                foreach (var openApiInfo in OpenApiInfoMap)
                {
                    c.SwaggerDoc(openApiInfo.Key, openApiInfo.Value);
                }

                string serviceName = (ConfigurationCenterExtension.nacosSetting?.ServiceName.IsNullOrWhiteSpace() == null || ConfigurationCenterExtension.nacosSetting?.ServiceName.IsNullOrWhiteSpace() == true) ? GlobalCoreSetting.ServiceName.ToLower() : ConfigurationCenterExtension.nacosSetting.ServiceName;
                c.AddServer(new OpenApiServer { Description = "gateway", Url = $"{GlobalCoreSetting.GatewayHost}/{serviceName}/" });
                c.AddServer(new OpenApiServer { Description = serviceName, Url = "/" });
                c.AddServer(new OpenApiServer { Description = "gateway-local", Url = $"/{serviceName}/" });

                //配置特殊类型映射
                c.MapType<TimeSpan>(() => new OpenApiSchema
                {
                    Type = "string",
                    Example = new Microsoft.OpenApi.Any.OpenApiString("00.00:00:00")
                });

                //swagger 配置 Bearer
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()//名称必须为“Bearer”，否者请求接口时Header不会带上Token
                {
                    //描述信息
                    Description = "请输入带有Bearer的Token，形如 Bearer {Token}",
                    //Description = "请输入 token",
                    //设置 API 密钥的位置
                    In = ParameterLocation.Header,
                    //Header对应名称
                    Name = "Authorization",
                    //验证类型，此处使用Api Key
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement {
                    { new OpenApiSecurityScheme
                        {
                        Reference = new OpenApiReference()
                            {
                                Id = "Bearer",
                                Type = ReferenceType.SecurityScheme
                            }
                    }, Array.Empty<string>() }
                });

                //swagger 显示注释
                var xmlFiles = Directory.GetFiles(System.AppContext.BaseDirectory, "*.xml");
                foreach (var file in xmlFiles) { c.IncludeXmlComments(file, true); }

                //显示枚举描述
                c.DocumentFilter<SwaggerEnumFilter>();
                //c.SchemaFilter<EnumSchemaFilter>();

                //上传文件
                c.OperationFilter<SwaggerFileUploadFilter>();
            });

            #endregion
            OnAppBuilderAction.SwaggeredAction?.Invoke(builder);
            return builder;
        }


    }

}
